﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Cmd.TypeConverters
{
    internal class TypeConverterHelpers
    {
        internal static List<ITypeConverter> Converters = new List<ITypeConverter>();

        public static ITypeConverter GetConverter(Type type)
        {
            if (type == null)
            {
                return null;
            }
            if (type.IsEnum && !ConverterExists(type))
            {
                ITypeConverter converter = new EnumConverter(type);
                RegisterConverter(converter);
            }
            if (type.IsArray && !ConverterExists(type))
            {
                ITypeConverter converter = new ArrayConverter(type);
                RegisterConverter(converter);
            }
            if (type.IsCollection() && !ConverterExists(type))
            {
                ITypeConverter converter = new CollectionConverter(type);
                RegisterConverter(converter);
            }
            return Converters.Where(item => item.BaseType == type).FirstOrDefault();
        }

        public static ITypeConverter GetConverter<T>()
        {
            if (typeof(T).IsEnum && !ConverterExists(typeof(T)))
            {
                ITypeConverter converter = new EnumConverter(typeof(T));
                RegisterConverter(converter);
            }
            return Converters.Where(item => item.BaseType == typeof(T)).FirstOrDefault();
        }

        public static void RegisterConverter(ITypeConverter converter)
        {
            if (ConverterExists(converter))
            {
                throw new ApplicationException("A converter for type '{0}' is already registered.");
            }
            Converters.Add(converter);
        }

        public static bool ConverterExists(ITypeConverter converter)
        {
            return Converters.Count(item => item.BaseType == converter.BaseType) > 0;
        }

        public static bool ConverterExists(Type type)
        {
            return Converters.Count(item => item.BaseType == type) > 0;
        }

        internal static void RefreshConverters(OptionSet options)
        {
            Converters.Clear();
            Assembly innerAssembly = Assembly.GetExecutingAssembly();

            foreach (Type type in innerAssembly.GetTypes())
            {
                if (type.GetInterface("ITypeConverter") != null &&
                    !type.ContainsGenericParameters &&
                    type != typeof(EnumConverter) &&
                    type != typeof(CollectionConverter) &&
                    type != typeof(ArrayConverter))
                {
                    ITypeConverter instance = Activator.CreateInstance(type) as ITypeConverter;
                    RegisterConverter(instance);
                }
            }

            ITypeConverter[] customConverters = options.GetCustomConverters();
            if (customConverters == null)
            {
                return;
            }

            foreach (ITypeConverter converter in customConverters)
            {
                RegisterConverter(converter);
            }
        }
    }
}
